package sis.studentinfo;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

public class Student {
	public static final int CREDITS_REQUIRED_FOR_FULL_TIME = 12;
	public static final String IN_STATE = "CO";
	public static final String TOO_MANY_NAME_PRTS_MSG = "Student name '%s' contains more than %d parts";
	static final int MAX_NAME_PARTS = 3;
	public static final Logger logger = Logger.getLogger(Student.class.getName());
	private ArrayList<Grade> grades = new ArrayList<Grade>(); 
	private String name ;
	private int credits;
	private String state = "";
	private GradingStrategy gradingStrategy = new RegularGradingStrategy();
	private String lastName;
	private String firstName = "";
	private String middleName = "";
	
	private List  charges = new ArrayList();
	private String id;
	
//	增强的枚举Grade，包含实例变量、构造函数、以及方法，枚举不能继承
	public enum Grade{
		A(4), 
		B(3), 
		C(2), 
		D(1), 
		F(0);
	private int points;
	Grade(int points){
		this.points = points;
	}
	int getPoints(){
		return points;
	}};
	
	public enum Flag{
		ON_CAMPUS(1),   //是否住校
		TAX_EXEMPT(2),  //是否免税
		MINOR(4),       //是否少数名族
		TROUBLERMAKER(8); //是否麻烦制造者
		
		private int mask;
		
		Flag(int mask){
			this.mask = mask;
		}
	}
	
	private int settings = 0x0;
	
	public Student(String fullName){
		this.name = fullName;
		credits = 0;
		List<String> nameParts = split(fullName);
		if (nameParts.size() > MAX_NAME_PARTS){
			String message = String.format(Student.TOO_MANY_NAME_PRTS_MSG,fullName,MAX_NAME_PARTS);
			Student.logger.info(message);
			throw new StudentNameFormatException(message);
		}
			
		setName(nameParts);
	}
	private List<String> split(String fullName) {
		List<String> results = new ArrayList<String>();
		for(String name:fullName.split(" "))
			results.add(name);
		return results;
	}
	private void setName(List<String> nameParts) {
		if (nameParts.size() == 1)
			this.lastName = nameParts.get(0);
		else if(nameParts.size() == 2){
			this.firstName = nameParts.get(0);
			this.lastName = nameParts.get(1);
		}
			
		else if (nameParts.size() == 3){
			this.firstName = nameParts.get(0);
			this.middleName = nameParts.get(1);
			this.lastName = nameParts.get(2);
		}
			
		
		
	}
	public String getName() {
		return name;
	}
	boolean isFullTime(){
		return credits >= CREDITS_REQUIRED_FOR_FULL_TIME;
	}
	public int getCredits() {
		return credits;
	}
	public void addCredits(int credits){
		this.credits += credits;
	}
	public boolean isInState() {
		return state.equals(Student.IN_STATE);
	}
	public void setState(String state){
		this.state = state;
	}
	public double getGpa() {
		Student.logger.fine("begin getGpa "+ System.currentTimeMillis());
		if(grades.isEmpty())
			return 0.0;
		double total = 0.0;
		for(Grade grade:grades){
			total += gradingStrategy.getGradePointsFor(grade);
		}		
		double result = total / grades.size();
		Student.logger.fine("end getGpa " + System.currentTimeMillis());
		return result;
	}
	public void addGrade(Grade grade) {
		grades.add(grade);
	}
	public void setGradingStrategy(GradingStrategy gradingStrategy) {
		this.gradingStrategy  = gradingStrategy;
		
	}
	public String getFirstName() {
		// TODO Auto-generated method stub
		return this.firstName;
	}
	public String getLastName() {
		// TODO Auto-generated method stub
		return this.lastName;
	}
	public String getMiddleName() {
		// TODO Auto-generated method stub
		return this.middleName;
	}
	public void addcharge(int charge) {
		charges.add(new Integer(charge));
	}
	public Object totalCharges() {
		int total =0;
		Iterator it =charges.iterator();
		while(it.hasNext()) {
			Integer charge = (Integer)it.next();
			total += charge.intValue();
		}
		return total;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getId() {
		// TODO Auto-generated method stub
		return this.id;
	}
	
	public void set(Flag... flags){
		for (Flag flag: flags)
			settings |= flag.mask;
	}
	
	public void unset(Flag... flags) {
		for (Flag flag: flags)
			settings &= ~flag.mask;
	}
	
	public boolean isOn(Flag flag) {
		return (settings & flag.mask) == flag.mask;
	}
	
	public boolean isOff(Flag flag) {
		return !isOn(flag);
	}
	
}
